﻿#ifndef FRAMEPROVIDER_H
#define FRAMEPROVIDER_H

#include <QObject>
#include <QPointer>
#include <QTimer>
#include <QElapsedTimer>
#include <QVideoFrame>
#include <QVideoSink>
#include "Decoder.h"
#include "ISynchronizer.h"
#include "VideoFrameFilter.h"
#include "FrameRenderer.h"


struct AVFrame;

class FrameProvider : public QObject
{
    Q_OBJECT

    Q_PROPERTY(FrameRenderer* frameRenderer READ frameRenderer WRITE setFrameRenderer NOTIFY frameRendererChanged)

    Q_PROPERTY(double currPTS READ currPTS)

    Q_PROPERTY(Decoder* decoder READ decoder WRITE setDecoder NOTIFY decoderChanged)

    Q_PROPERTY(ISynchronizer* synchronizer READ synchronizer WRITE setSynchronizer NOTIFY synchronizerChanged)

public:
    explicit FrameProvider(QObject* parent = nullptr);
    ~FrameProvider();

    QVideoSink *videoSink() const;
    void setVideoSink(QVideoSink *newVideoSink);

    FrameRenderer *frameRenderer() const;
    void setFrameRenderer(FrameRenderer *newFrameRenderer);

    double currPTS() const;

    Decoder *decoder() const;
    void setDecoder(Decoder *newDecoder);

    ISynchronizer *synchronizer() const;
    void setSynchronizer(ISynchronizer *newSynchronizer);

    Q_INVOKABLE int64_t serialTimepoint() {
        return m_serial.timepoint;
    }
    Q_INVOKABLE int64_t serialId() {
        return m_serial.id;
    }

signals:
    void videoSinkChanged();

    void decoderChanged();

    void synchronizerChanged();

    void frameRendererChanged();

private slots:
    void onUpdateTimeout();

private:

    QVideoFrame copyAVFrameToQVideoFrame(AVFrame* avFrame);

    void deliverFrame();

    AVFrame* nextFrame();

    int frameTimeCheck(int64_t pts, const AVFrame* frame);

    DecodecSerial m_serial;

    QTimer m_updateTimer;

    AVRational m_timebase = {0, 1};

    AVFrame* m_curFrame = nullptr;

    ISynchronizer* m_synchronizer = nullptr;

    Decoder *m_decoder = nullptr;

    VideoFrameFilter *m_filter = nullptr;

    FrameRenderer *m_frameRenderer = nullptr;
};

#endif // FRAMEPROVIDER_H
